package jmine.tec.subscription;

import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Gerencia {@link Subscription}'s
 * 
 * @author takeshi
 */
public interface SubscriptionManager {

    /**
     * Cria um novo {@link SubscriptionSet} que nao expira
     * 
     * @return {@link SubscriptionSet}
     */
    SubscriptionSet newSubscription();

    /**
     * Cria um novo {@link SubscriptionSet}
     * 
     * @param timeout timeout
     * @param unit {@link TimeUnit}
     * @return {@link SubscriptionSet}
     */
    SubscriptionSet newExpiringSubscription(long timeout, TimeUnit unit);

    /**
     * Devolve a {@link SubscriptionSet} associado ao token passado
     * 
     * @param token long
     * @return {@link SubscriptionSet}
     */
    SubscriptionSet getSubscriptionSet(long token);

    /**
     * Inscreve-se a uma nova {@link Subscription} no {@link Publisher} e {@link SubscriptionSettings} passados, adicionando ao
     * {@link SubscriptionSet}
     * 
     * @param s {@link SubscriptionSet}
     * @param source {@link Publisher}
     * @param settings {@link SubscriptionSettings}
     * @return {@link Subscription}
     * @param <P> o tipo concreto da publication
     */
    <P extends Publication> Subscription addSubscription(SubscriptionSet s, Publisher<P> source, SubscriptionSettings settings);

    /**
     * Adiciona a subscription de maneira lazy. Analogo a {@link #addSubscription(long, Publisher, SubscriptionSettings)} , exceto que a
     * subscricao propriamente dita vai ocorrer em algum momento do futuro, denotada pelo {@link Future} devolvida
     * 
     * @param <P> o tipo da publication.
     * @param subscriptionSet o {@link SubscriptionSet} que vai conter a subscription
     * @param source a fonte
     * @param settings o {@link SubscriptionSettings}
     * @return {@link Future} de {@link Subscription}
     */
    <P extends Publication> Future<Subscription> addLazySubscription(long subscriptionSet, Publisher<P> source,
            SubscriptionSettings settings);

    /**
     * Adiciona a subscription de maneira lazy. Analogo a
     * {@link #addSubscription(long, Publisher, SubscriptionSettings, PublicationListener)} , exceto que a subscricao propriamente dita vai
     * ocorrer em algum momento do futuro, denotada pelo {@link Future} devolvida
     * 
     * @param <P> o tipo da publication.
     * @param subscriptionSet o {@link SubscriptionSet} que vai conter a subscription
     * @param source a fonte
     * @param settings o {@link SubscriptionSettings}
     * @param listener o {@link PublicationListener} a ser notificado
     * @return {@link Future} de {@link Subscription}
     */
    <P extends Publication> Future<Subscription> addLazySubscription(long subscriptionSet, Publisher<P> source,
            SubscriptionSettings settings, PublicationListener<P> listener);

    /**
     * Inscreve-se a uma nova {@link Subscription} no {@link Publisher} e {@link SubscriptionSettings} passados, adicionando ao
     * {@link SubscriptionSet}
     * 
     * @param s {@link SubscriptionSet}
     * @param source {@link Publisher}
     * @param settings {@link SubscriptionSettings}
     * @param listener {@link PublicationListener}
     * @return {@link Subscription}
     * @param <P> o tipo concreto da publication
     */
    <P extends Publication> Subscription addSubscription(SubscriptionSet s, Publisher<P> source, SubscriptionSettings settings,
            PublicationListener<P> listener);

    /**
     * Inscreve-se a uma nova {@link Subscription} no {@link Publisher} e {@link SubscriptionSettings} passados, adicionando ao
     * {@link SubscriptionSet} com o token passado
     * 
     * @param s {@link SubscriptionSet}
     * @param source {@link Publisher}
     * @param settings {@link SubscriptionSettings}
     * @param listener {@link PublicationListener}
     * @return {@link Subscription}
     * @param <P> o tipo concreto da publication
     */
    <P extends Publication> Subscription addSubscription(long s, Publisher<P> source, SubscriptionSettings settings,
            PublicationListener<P> listener);

    /**
     * Inscreve-se a uma nova {@link Subscription} no {@link Publisher} e {@link SubscriptionSettings} passados, adicionando ao
     * {@link SubscriptionSet} com o token passado
     * 
     * @param s {@link SubscriptionSet}
     * @param source {@link Publisher}
     * @param settings {@link SubscriptionSettings}
     * @return {@link Subscription}
     * @param <P> o tipo concreto da publication
     */
    <P extends Publication> Subscription addSubscription(long s, Publisher<P> source, SubscriptionSettings settings);

    /**
     * Cancela uma {@link Subscription}.
     * 
     * @param s {@link Subscription}
     * @param source {@link Publisher}
     * @param settings {@link SubscriptionSettings}
     */
    void unsubscribe(SubscriptionSet s, Publisher<?> source, SubscriptionSettings settings);

    /**
     * Cancela todos os {@link Subscription} presentes no {@link SubscriptionSet} e libera recursos associados ao {@link SubscriptionSet}
     * 
     * @param su o {@link SubscriptionSet}
     */
    void cancelSubscription(SubscriptionSet su);

    /**
     * Devolve o conjunto de publicacoes associadas ao {@link SubscriptionSet}. Clientes desta classe devem verificar o
     * {@link Subscription#getVersion()} para saber se houve mudancas entre a versao anterior e esta.
     * 
     * @param set {@link SubscriptionSet}
     * @return {@link Map} de {@link Subscription} para {@link Publication}
     */
    Map<Subscription, Publication> getChanges(SubscriptionSet set);

    /**
     * Devolve a {@link Publication} associada ao {@link Subscription} do {@link SubscriptionSet} com o token passado. Devolve null se nao
     * houveram mudancas desde a ultima vez que este metodo ou {@link #getChanges(SubscriptionSet)} foi chamado.
     * 
     * @param set {@link SubscriptionSet}
     * @param subscriptionToken o token da subscription
     * @return {@link Publication} ou null
     */
    Publication getChanges(SubscriptionSet set, long subscriptionToken);

    /**
     * Cancela a inscricao de uma {@link Subscription}
     * 
     * @param set {@link SubscriptionSet}
     * @param subscriptionToken long
     */
    void unsubscribe(SubscriptionSet set, long subscriptionToken);

}
